package cn.itcast.nems.journal.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.itcast.ic.common.bean.Page;
import cn.itcast.ic.common.exception.BizException;
import cn.itcast.ic.common.exception.v2.BizExceptionProducer;
import cn.itcast.nems.approval.bpm.eventstrategy.BpmEventStrategy;
import cn.itcast.nems.approval.dao.entity.ApprovalForm;
import cn.itcast.nems.approval.enumeration.ApprovalFormStateEnum;
import cn.itcast.nems.approval.service.ApprovalAdditionalFormService;
import cn.itcast.nems.approval.service.ApprovalFormFlowService;
import cn.itcast.nems.approval.service.ApprovalFormService;
import cn.itcast.nems.base.api.ClazzApi;
import cn.itcast.nems.base.api.SchoolApi;
import cn.itcast.nems.base.dao.entity.Paymentchannel;
import cn.itcast.nems.base.dto.ClazzDTO;
import cn.itcast.nems.base.dto.SchoolDTO;
import cn.itcast.nems.common.account.AccountHolder;
import cn.itcast.nems.common.enumeration.BizNumberTypeEnum;
import cn.itcast.nems.common.enumeration.CustomBizError;
import cn.itcast.nems.common.enumeration.NemsErrorBodyEnum;
import cn.itcast.nems.common.service.BizNumberService;
import cn.itcast.nems.common.utils.BigDecimalUtil;
import cn.itcast.nems.journal.enumeration.JournalStateEnum;
import cn.itcast.nems.journal.service.JournalFundTransferService;
import cn.itcast.nems.oldems.dto.oldapi.EmsApiResult;
import cn.itcast.nems.oldems.service.PaymentchannelService;
import cn.itcast.nems.oldems.service.sync.OldEmsSyncService;
import cn.itcast.nems.order.api.OrderApi;
import cn.itcast.nems.order.dto.PaymentFlowDTO;
import cn.itcast.nems.studentrecord.api.StudentRecordPaidApi;
import cn.itcast.nems.studentrecord.constant.ReferenceTypeEnum;
import cn.itcast.nems.studentrecord.dao.condition.ApprovalType;
import cn.itcast.nems.studentrecord.dao.condition.ReceivableAdjustmentState;
import cn.itcast.nems.studentrecord.dao.dataobject.StudentRecordFundFlowSchoolChannelDO;
import cn.itcast.nems.studentrecord.dao.entity.JournalFundTransfer;
import cn.itcast.nems.studentrecord.dao.entity.StudentRecord;
import cn.itcast.nems.studentrecord.dao.mapper.JournalFundTransferMapper;
import cn.itcast.nems.studentrecord.dto.StudentRecordPaidDTO;
import cn.itcast.nems.studentrecord.enumeration.FundFlowPaymentTypeEnum;
import cn.itcast.nems.studentrecord.enumeration.StudentRecordErrorBodyEnum;
import cn.itcast.nems.studentrecord.service.studentrecord.StudentRecordFundFlowService;
import cn.itcast.nems.studentrecord.service.studentrecord.StudentRecordService;
import cn.itcast.nems.studentrecord.service.studentrecord.StudentRecordStudentRelationshipService;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.*;

/**
 * <p>
 * 学费转移凭单 服务实现类
 * </p>
 *
 * @author 陈早庆
 * @since 2024-02-23
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class JournalFundTransferServiceImpl extends ServiceImpl<JournalFundTransferMapper, JournalFundTransfer> implements JournalFundTransferService, BpmEventStrategy {
    private final ApprovalFormFlowService approvalFormFlowService;
    private final ApprovalFormService approvalFormService;
    private final StudentRecordService studentRecordService;
    private final StudentRecordPaidApi studentRecordPaidApi;
    private final BizNumberService bizNumberService;
    private final ClazzApi clazzApi;
    private final StudentRecordFundFlowService studentRecordFundFlowService;
    private final SchoolApi schoolApi;
    private final PaymentchannelService paymentchannelService;
    private final StudentRecordStudentRelationshipService studentRecordStudentRelationshipService;
    private final OrderApi orderApi;
    final ApprovalAdditionalFormService approvalAdditionalFormService;
    private final OldEmsSyncService oldEmsSyncService;
    private static final ObjectMapper objectMapper = new ObjectMapper()
            .setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE)
            .configure(JsonGenerator.Feature.IGNORE_UNKNOWN, true);

    @Override
    public Page<JournalFundTransfer> listPage(Integer pageNumber, Integer pageSize, JournalFundTransfer params) {
        ApprovalType approvalType = params.getApprovalType();
        // 控制数据权限
        if (approvalType == ApprovalType.ALL) {
            if (!AccountHolder.hasEmployeeGroups()) {
                return Page.of(pageNumber, pageSize, 0, null);
            }
            params.setEmployeeGroups(AccountHolder.getEmployeeGroups());
        }
        // 筛选条件处理
        this.listPageParams(params);
        IPage<JournalFundTransfer> pageData = baseMapper.listPage(new com.baomidou.mybatisplus.extension.plugins.pagination.Page<>(pageNumber, pageSize), params);
        if (CollectionUtil.isEmpty(pageData.getRecords())) {
            return Page.of(pageNumber, pageSize, 0, null);
        }
        return Page.of(pageNumber, pageSize, (int) pageData.getTotal(), pageData.getRecords());
    }

    @Override
    public Page<Map> searchClazzes(Integer pageNumber, Integer pageSize, JournalFundTransfer params) {
        ApprovalType approvalType = params.getApprovalType();
        // 数据权限
        if (approvalType == ApprovalType.ALL) {
            if (!AccountHolder.hasEmployeeGroups()) {
                return Page.of(pageNumber, pageSize, 0, null);
            }
            params.setEmployeeGroups(AccountHolder.getEmployeeGroups());
        }
        // 筛选条件处理
        this.listPageParams(params);
        IPage<Map> pageData = baseMapper.searchClazzes(new com.baomidou.mybatisplus.extension.plugins.pagination.Page<>(pageNumber, pageSize), params);
        if (CollectionUtil.isEmpty(pageData.getRecords())) {
            return Page.of(pageNumber, pageSize, 0, null);
        }
        return Page.of(pageNumber, pageSize, (int) pageData.getTotal(), pageData.getRecords());
    }

    /**
     * 筛选条件处理
     *
     * @param params
     */
    private void listPageParams(JournalFundTransfer params) {
        ApprovalType approvalType = params.getApprovalType();
        params.setJournalType(ApprovalFormService.JournalType.FUND_TRANSFER.name());
        if (approvalType == ApprovalType.MY_COMMIT) {
            // 我提交的
            params.setFlowCreatedBy(AccountHolder.getRequiredAccount());
            params.setCreatedBy(AccountHolder.getRequiredAccount());
        } else if (approvalType == ApprovalType.WAIT_APPROVAL) {
            // 待办凭单
            List<String> journalIdFormIds = approvalFormService.getJournalIdFormIds(ApprovalFormService.JournalType.FUND_TRANSFER);
            if (CollectionUtil.isNotEmpty(journalIdFormIds)) {
                params.setFormIds(journalIdFormIds);
            }
            params.setFlowCreatedBy(AccountHolder.getRequiredAccount());
            params.setExcludeState(ReceivableAdjustmentState.DRAFT.name());
        } else if (approvalType == ApprovalType.APPROVED) {
            // 已办凭单
            List<String> journalIdFormIds = approvalFormService.getJournalIdFormIds(ApprovalFormService.JournalType.FUND_TRANSFER);
            if (CollectionUtil.isNotEmpty(journalIdFormIds)) {
                params.setFormIds(journalIdFormIds);
            }
            params.setFlowCreatedBy(AccountHolder.getRequiredAccount());
            params.setExcludeState(ReceivableAdjustmentState.DRAFT.name());
        } else if (approvalType == ApprovalType.ALL) {
            // 全部凭单
            params.setExcludeState(ReceivableAdjustmentState.DRAFT.name());
        }
    }

    @Override
    public JournalFundTransfer getById(String id) {
        JournalFundTransfer journal = baseMapper.getById(id);
        ApprovalForm approvalForm = approvalFormService.getOne(new LambdaQueryWrapper<ApprovalForm>().eq(ApprovalForm::getJournalId, id)
                .eq(ApprovalForm::getDeletedFlag, Boolean.FALSE)
                .notIn(ApprovalForm::getState, ApprovalFormStateEnum.CANCELED.name()).last(" order by  created_datetime desc limit 1"));
        journal.setFormId(Objects.nonNull(approvalForm) ? approvalForm.getId() : null);
        Integer studentId = studentRecordStudentRelationshipService.findStudentId(journal.getOriginStudentRecordId());
        journal.setStudentId(studentId);
        return journal;
    }

    @Override
    @Transactional
    public String create(JournalFundTransfer params) {
        String originStudentRecordId = params.getOriginStudentRecordId();
        Integer originClazzId = params.getOriginClazzId();
        String transferAmountStr = params.getTransferAmount();
        cn.hutool.core.lang.Assert.notNull(transferAmountStr, () -> new BizException(CustomBizError.message(CustomBizError.PARAM_EMPTY, "本次转移金额不能为空")));
        BigDecimal transferAmount = new BigDecimal(params.getTransferAmount());
        params.setTransferAmount(String.valueOf(BigDecimalUtil.bigDecimalToCentInt(transferAmount.setScale(2, RoundingMode.HALF_UP))));
        // 费用核验
        Boolean exists = this.fundTransferExistsAmount(params);
        cn.hutool.core.lang.Assert.isTrue(!exists, BizExceptionProducer.produce(StudentRecordErrorBodyEnum.BAD_REQUEST, "没有可转移金额"));
        params.setId(bizNumberService.next(BizNumberTypeEnum.FUND_TRANSFER));
        // 根据班级id获取name
        ClazzDTO originClazz = clazzApi.queryByClassId(params.getOriginClazzId());
        Assert.notNull(originClazz, "转出班级不存在");
        params.setOriginClazzName(originClazz.getClassName());
        // 目标班级
        ClazzDTO targetClazz = clazzApi.queryByClassId(params.getTargetClazzId());
        Assert.notNull(targetClazz, "目标班级不存在");
        params.setTargetClazzName(targetClazz.getClassName());
        params.setTargetClazzSubjectId(targetClazz.getSubjectId());
        params.setTargetClazzSubjectName(targetClazz.getSubjectName());
        params.setTargetClazzCampusId(targetClazz.getSchoolId());
        params.setTargetClazzCampusName(targetClazz.getSchoolName());
        Assert.isTrue(targetClazz.getSchoolId().equals(params.getTargetClazzCampusId()), "校区不匹配");
        if (StringUtils.hasText(params.getCampusId())) {
            // 获取校区名称
            SchoolDTO schoolDTO = schoolApi.findById(params.getCampusId());
            if (schoolDTO != null) {
                params.setCampusName(schoolDTO.getName());
            }
        }
        if (StringUtils.hasText(params.getChannelCode())) {
            Paymentchannel paymentchannel = paymentchannelService.getById(params.getChannelCode());
            if (paymentchannel != null) {
                params.setChannelName(paymentchannel.getName());
            }
        }
        List<StudentRecordFundFlowSchoolChannelDO> studentRecordFundFlowSchoolChannelDOS = studentRecordFundFlowService.selectByStudentRecordIdClazzId(originStudentRecordId, originClazzId);
        if (studentRecordFundFlowSchoolChannelDOS != null && studentRecordFundFlowSchoolChannelDOS.size() == 1) {
            StudentRecordFundFlowSchoolChannelDO studentRecordFundFlowSchoolChannelDO = studentRecordFundFlowSchoolChannelDOS.get(0);
            params.setOriginCampusId(studentRecordFundFlowSchoolChannelDO.getOriginCampusId());
            params.setOriginCampusName(studentRecordFundFlowSchoolChannelDO.getOriginCampusName());
            params.setOriginChannelCode(studentRecordFundFlowSchoolChannelDO.getOriginChannelCode());
            params.setOriginChannelName(studentRecordFundFlowSchoolChannelDO.getOriginChannelName());
            params.setChannelType("SINGLE_CHANNEL");
        } else if (studentRecordFundFlowSchoolChannelDOS != null && studentRecordFundFlowSchoolChannelDOS.size() > 1) {
            params.setChannelType("MORE_CHANNEL");
        } else {
            params.setChannelType("");
        }
        Assert.isTrue(targetClazz.getSchoolId().equals(params.getTargetClazzCampusId()), "校区不匹配");
        if (!StringUtils.hasText(params.getRemark())) {
            params.setRemark("");
        }
        params.setCreatedBy(AccountHolder.getRequiredAccount());
        int insert = baseMapper.insert(params);
        cn.hutool.core.lang.Assert.isTrue(insert > 0, BizExceptionProducer.produce(StudentRecordErrorBodyEnum.BAD_REQUEST, "创建失败"));
        // 不是草稿并且是提交启动流程
        if (!JournalStateEnum.DRAFT.name().equals(params.getState()) && JournalStateEnum.PENDING.name().equals(params.getState())) {
            // 启动流程
            this.startProcess(params);
        }
        return params.getId();
    }

    @Override
    public Boolean delete(String id) {
        JournalFundTransfer journal = baseMapper.selectById(id);
        Assert.notNull(journal, "数据不存在");
        Assert.isTrue("DRAFT".equals(journal.getState()), "只能删除草稿状态的数据");
        Assert.isTrue(journal.getCreatedBy().equals(AccountHolder.getRequiredAccount()), "只能删除自己创建的数据");
        return lambdaUpdate().eq(JournalFundTransfer::getId, id)
                .set(JournalFundTransfer::getDeletedBy, AccountHolder.getRequiredAccount())
                .set(JournalFundTransfer::getDeletedDatetime, LocalDateTime.now())
                .set(JournalFundTransfer::getDeletedFlag, Boolean.TRUE).update();
    }

    @Override
    @Transactional
    public Boolean update(JournalFundTransfer params) {
        String id = params.getId();
        String originStudentRecordId = params.getOriginStudentRecordId();
        Integer originClazzId = params.getOriginClazzId();
        String transferAmountStr = params.getTransferAmount();
        cn.hutool.core.lang.Assert.notNull(id, () -> new BizException(CustomBizError.message(CustomBizError.PARAM_EMPTY, "id不能为空")));
        cn.hutool.core.lang.Assert.notNull(transferAmountStr, () -> new BizException(CustomBizError.message(CustomBizError.PARAM_EMPTY, "本次转移金额不能为空")));
        // 仅支持草稿修改
        // 检查数据是否存在，并且状态合理
        JournalFundTransfer journal = baseMapper.selectById(params.getId());
        cn.hutool.core.lang.Assert.notNull(journal, BizExceptionProducer.produce(StudentRecordErrorBodyEnum.BAD_REQUEST, "该学员有在途凭单"));
        if (StringUtils.hasText(params.getState())) {
            // 审批类型：{DRAFT：草稿，PENDING：待审批，APPROVING：审批中，REJECTED：审批未通过，FINISHED：已完成}
            cn.hutool.core.lang.Assert.isTrue(List.of("DRAFT", "PENDING", "COMMIT").contains(params.getState()), BizExceptionProducer.produce(StudentRecordErrorBodyEnum.BAD_REQUEST, "只能存为草稿或提交"));
        }
        BigDecimal transferAmount = new BigDecimal(params.getTransferAmount());
        params.setTransferAmount(String.valueOf(BigDecimalUtil.bigDecimalToCentInt(transferAmount.setScale(2, RoundingMode.HALF_UP))));
        Boolean exists = fundTransferExistsAmount(params);
        cn.hutool.core.lang.Assert.isTrue(!exists, BizExceptionProducer.produce(StudentRecordErrorBodyEnum.BAD_REQUEST, "没有可转移金额"));
        // 根据班级id获取name
        ClazzDTO originClazz = clazzApi.queryByClassId(params.getOriginClazzId());
        Assert.notNull(originClazz, "转出班级不存在");
        params.setOriginClazzName(originClazz.getClassName());
        // 目标班级
        ClazzDTO targetClazz = clazzApi.queryByClassId(params.getTargetClazzId());
        Assert.notNull(targetClazz, "目标班级不存在");
        params.setTargetClazzName(targetClazz.getClassName());
        params.setTargetClazzSubjectId(targetClazz.getSubjectId());
        params.setTargetClazzSubjectName(targetClazz.getSubjectName());
        params.setTargetClazzCampusId(targetClazz.getSchoolId());
        params.setTargetClazzCampusName(targetClazz.getSchoolName());
        if (StringUtils.hasText(params.getCampusId())) {
            // 获取校区名称
            SchoolDTO schoolDTO = schoolApi.findById(params.getCampusId());
            if (schoolDTO != null) {
                params.setCampusName(schoolDTO.getName());
            }
        }
        if (StringUtils.hasText(params.getChannelCode())) {
            Paymentchannel paymentchannel = paymentchannelService.getById(params.getChannelCode());
            if (paymentchannel != null) {
                params.setChannelName(paymentchannel.getName());
            }
        }
        if (StringUtils.hasText(params.getState())) {
            List<StudentRecordFundFlowSchoolChannelDO> studentRecordFundFlowSchoolChannelDOS = studentRecordFundFlowService.selectByStudentRecordIdClazzId(originStudentRecordId, originClazzId);
            if (studentRecordFundFlowSchoolChannelDOS != null && studentRecordFundFlowSchoolChannelDOS.size() == 1) {
                StudentRecordFundFlowSchoolChannelDO studentRecordFundFlowSchoolChannelDO = studentRecordFundFlowSchoolChannelDOS.get(0);
                params.setOriginCampusId(studentRecordFundFlowSchoolChannelDO.getOriginCampusId());
                params.setOriginCampusName(studentRecordFundFlowSchoolChannelDO.getOriginCampusName());
                params.setOriginChannelCode(studentRecordFundFlowSchoolChannelDO.getOriginChannelCode());
                params.setOriginChannelName(studentRecordFundFlowSchoolChannelDO.getOriginChannelName());
                params.setChannelType("SINGLE_CHANNEL");
            } else if (studentRecordFundFlowSchoolChannelDOS != null && studentRecordFundFlowSchoolChannelDOS.size() > 1) {
                params.setChannelType("MORE_CHANNEL");
            } else {
                params.setChannelType("");
            }
        }
        Assert.isTrue(targetClazz.getSchoolId().equals(params.getTargetClazzCampusId()), "校区不匹配");
        if (!StringUtils.hasText(params.getRemark())) {
            params.setRemark("");
        }
        params.setModifiedBy(AccountHolder.getRequiredAccount());
        int updateById = baseMapper.updateById(params);
        cn.hutool.core.lang.Assert.isTrue(updateById > 0, BizExceptionProducer.produce(StudentRecordErrorBodyEnum.BAD_REQUEST, "编辑失败"));
        if (StringUtils.hasText(params.getState())) {
            // 不是草稿并且是提交启动流程
            if (!JournalStateEnum.DRAFT.name().equals(params.getState()) && JournalStateEnum.PENDING.name().equals(params.getState())) {
                // 启动流程
                this.startProcess(params);
            }
        }
        return Boolean.TRUE;
    }

    @Override
    public Boolean fundTransferExistsAmount(JournalFundTransfer params) {
        // TODO 检查有可转移金额
        String originStudentRecordId = params.getOriginStudentRecordId();
        // 本次转移金额
        Integer transferAmount = Integer.valueOf(params.getTransferAmount());
        // TODO 获取转出班级学籍
        StudentRecord originStudentRecord = studentRecordService.getStudentRecordById(originStudentRecordId);
        cn.hutool.core.lang.Assert.notNull(originStudentRecord, BizExceptionProducer.produce(StudentRecordErrorBodyEnum.NOT_EXISTS));
        // 已付金额
        // 可转移金额max_transfer_amount：（转入金额transfer_from_amount + 已付金额paid_amount - 退费合计refund_amount - 转出金额transfer_out_amount） - 应付金额amount_due
        Integer maxTransferAmount = (originStudentRecord.getTransferFromAmount() + originStudentRecord.getPaidAmount()) - (originStudentRecord.getRefundAmount() - originStudentRecord.getTransferOutAmount()) - originStudentRecord.getAmountDue();
        params.setMaxTransferAmount(String.valueOf(maxTransferAmount));
        if (!(maxTransferAmount >= transferAmount)) {
            // 没有可转移金额返回
            return Boolean.TRUE;
        }
        // 防止超额转出
        Integer sumTransferAmount = baseMapper.getSumTransferAmount(originStudentRecordId);
        cn.hutool.core.lang.Assert.isTrue(!((sumTransferAmount == null ? 0 : sumTransferAmount) > maxTransferAmount), BizExceptionProducer.produce(StudentRecordErrorBodyEnum.BAD_REQUEST, "转出金额不能大于支付金额"));


        // TODO 获取转入班级学籍
        String targetStudentRecordId = params.getTargetStudentRecordId();
        StudentRecord targetStudentRecord = studentRecordService.getStudentRecordById(targetStudentRecordId);
        cn.hutool.core.lang.Assert.notNull(targetStudentRecord, BizExceptionProducer.produce(StudentRecordErrorBodyEnum.NOT_EXISTS));
        // 交费合计targetActualPaidAmount：转入金额transfer_from_amount + 已付金额paid_amount - 退费合计refund_amount - 转出金额transfer_out_amount
        Integer transferFromAmount = (targetStudentRecord.getTransferFromAmount() + targetStudentRecord.getPaidAmount()) - targetStudentRecord.getRefundAmount() - targetStudentRecord.getTransferOutAmount();
        params.setTargetActualPaidAmount(String.valueOf(transferFromAmount));
        // 转移后交费合计targetNewActualPaidAmount：交费合计targetActualPaidAmount + 转移金额transfer_amount
        params.setTargetNewActualPaidAmount(String.valueOf(transferFromAmount + transferAmount));
        return Boolean.FALSE;
    }

    @Override
    @Transactional
    public Boolean flow(String id) {
        JournalFundTransfer journal = baseMapper.selectById(id);
        log.info("【提交】根据ID查询凭单头 ，ID：{}，查询结果：{}", id, JSON.toJSONString(journal));
        cn.hutool.core.lang.Assert.isTrue(JournalStateEnum.DRAFT.name().equalsIgnoreCase(journal.getState()), BizExceptionProducer.produce(StudentRecordErrorBodyEnum.REQUEST_JOURNAL_RENEWAL_STATE_ERROR));
        String result = this.startProcess(journal);
        log.info("【提交】流程审批单详情：{}", result);
        return lambdaUpdate().eq(JournalFundTransfer::getId, id).set(JournalFundTransfer::getState, JournalStateEnum.PENDING.name()).update();
    }

    // 启动流程
    private String startProcess(JournalFundTransfer params) {
        // 锁定学籍
        studentRecordService.locks(Set.of(params.getOriginStudentRecordId()), ReferenceTypeEnum.FUND_TRANSFER, params.getId());
        String id = params.getId();
        HashMap<String, Object> variables = new HashMap<>();
//      2、是否特殊审批  special_approval （"true"， "false"）
        variables.put("special_approval", String.valueOf(params.getSpecialFlag()));
        // 经手部门
        variables.put("handling_department", "发起人部门");
        String start = approvalFormService.start(ApprovalFormService.JournalType.FUND_TRANSFER, id, variables, null);
        log.info("【提交】流程审批单详情：{}", start);
        return start;
    }

    @Override
    @Transactional
    public String getStrategyName() {
        return ApprovalFormService.JournalType.FUND_TRANSFER.name();
    }

    @Override
    @Transactional
    public void inform(String formID, String targetAssignee) {
        approvalFormFlowService.inform(formID, targetAssignee);
    }

    @Transactional
    @Override
    public Runnable finish(String formID) {
        ApprovalForm approvalForm = approvalFormService.getByBusinessKey(formID);
        if (approvalForm == null) {
            return null;
        }
        String journalId = approvalForm.getJournalId();
        log.info("【审批流程所有节点全部审批通过】查询审批单详情：{}", JSON.toJSONString(approvalForm));
        JournalFundTransfer journal = baseMapper.selectById(journalId);
        log.info("【审批流程所有节点全部审批通过】查询凭单详情：{}", JSON.toJSONString(journal));
        if (journal.getState().equals(JournalStateEnum.FINISHED.name())) {
            log.info("【审批流程所有节点全部审批通过】已通过状态无需处理，ID：{}", journalId);
            return null;
        }
        // 默认：全部审批通过审批完成
        ApprovalFormStateEnum approvalFormStateEnum = ApprovalFormStateEnum.FINISHED;
        Integer transferAmount = Integer.valueOf(journal.getTransferAmount());
        EmsApiResult dropout = oldEmsSyncService.fundTransfer(journal.getOriginStudentRecordId(), journal.getTargetStudentRecordId(), "SINGLE_CHANNEL".equals(journal.getChannelType()) ? false : true, journal.getChannelCode(), "3", journal.getCreatedBy(), journal.getOriginChannelCode(), transferAmount);
        if (!dropout.isSuccess()) {
            approvalFormStateEnum = ApprovalFormStateEnum.APPROVING;
        }
        lambdaUpdate().eq(JournalFundTransfer::getId, journalId).set(JournalFundTransfer::getState, approvalFormStateEnum.name()).update();
        log.info("【审批流程所有节点全部审批通过】修改状态 ID：{}， 修改状态：{}", journalId, approvalFormStateEnum.name());
        if (approvalFormStateEnum == ApprovalFormStateEnum.FINISHED) {
            // 处理本地的审批流程单
            approvalFormService.finish(formID);
        } else {
            // 失败
            approvalFormService.fail(formID, dropout.getErrorMessage());
            return null;
        }
        // 费用转出班级
        this.processOriginalClazz(journal);
        // 费用转入班级
        this.processTargetClazz(journal);
        // 解锁学籍
        studentRecordService.unlock(journal.getOriginStudentRecordId());
        return null;
    }

    // 费用转出班级
    private void processOriginalClazz(JournalFundTransfer journal) {
        String originStudentRecordId = journal.getOriginStudentRecordId();
        Integer clazzId = journal.getOriginClazzId();
        String clazzName = journal.getOriginClazzName();
        Integer amount = Integer.valueOf(journal.getTransferAmount());
//        // 增加费用转出班级"负向流水"
//        this.createStudentRecordFundFlow(journal.getId(), originStudentRecordId, clazzId, journal.getOriginClazzName(), journal.getBizDate(), -Integer.valueOf(amount), journal.getRemark(), journal.getChannelCode(), journal.getChannelName());
//        // 修改学籍 e2_student_record “转出金额 transfer_out_amount”
//        // // 待生效的学籍，在有金额转入后，变为已生效学籍
//        studentRecordService.updateRefundAmountByIdOrClazzId(originStudentRecordId, clazzId, Integer.valueOf(amount));
        String id = journal.getId();
        String remark = journal.getRemark();
        String channelCode = StringUtils.hasText(journal.getChannelCode()) ? journal.getChannelCode() : "";
        String channelName = StringUtils.hasText(journal.getChannelName()) ? journal.getChannelName() : "";
        LocalDateTime bizDate = journal.getBizDate();
        this.extracted(originStudentRecordId, id, -amount, bizDate, channelCode, channelName, remark, clazzId, clazzName);
    }

    // 费用转入班级
    private void processTargetClazz(JournalFundTransfer journal) {
        String targetStudentRecordId = journal.getTargetStudentRecordId();
        Integer clazzId = journal.getTargetClazzId();
        String clazzName = journal.getTargetClazzName();
        Integer amount = Integer.valueOf(journal.getTransferAmount());
//        // 增加费用转入班级"正向流水"
//        this.createStudentRecordFundFlow(journal.getId(), targetStudentRecordId, clazzId, journal.getTargetClazzName(), journal.getBizDate(), Integer.valueOf(amount), journal.getRemark(), journal.getChannelCode(), journal.getChannelName());
//        // 修改学籍 e2_student_record "转入金额 transfer_from_amount"
//        // 待生效的学籍，在有金额转入后，变为已生效学籍
//        studentRecordService.updatePaidAmountByIdOrClazzId(targetStudentRecordId, clazzId, Integer.valueOf(amount));
        String id = journal.getId();
        String remark = journal.getRemark();
        String channelCode = StringUtils.hasText(journal.getChannelCode()) ? journal.getChannelCode() : "";
        String channelName = StringUtils.hasText(journal.getChannelName()) ? journal.getChannelName() : "";
        LocalDateTime bizDate = journal.getBizDate();
        this.extracted(targetStudentRecordId, id, amount, bizDate, channelCode, channelName, remark, clazzId, clazzName);
    }

    private void extracted(String originStudentRecordId, String id, Integer amount, LocalDateTime bizDate, String channelCode, String channelName, String remark, Integer clazzId, String clazzName) {
        String orderId = studentRecordService.findOrderId(originStudentRecordId);
        if (StringUtils.hasText(orderId)) {
            PaymentFlowDTO flowDTO = new PaymentFlowDTO();
            flowDTO.setOrderId(orderId);
            flowDTO.setJournalType(FundFlowPaymentTypeEnum.FUND_TRANSFER.name());
            flowDTO.setJournalNo(id);
            flowDTO.setAmount(amount);
            flowDTO.setCharge(0);
            flowDTO.setChargeRate(BigDecimal.ZERO);
            flowDTO.setBizDate(bizDate);
            flowDTO.setPaymentMethodCode("");
            flowDTO.setPaymentMethodName("");
            flowDTO.setPaymentAccountCode(channelCode);
            flowDTO.setPaymentAccountName(channelName);
            flowDTO.setRemark(StringUtils.hasText(remark) ? remark : FundFlowPaymentTypeEnum.FUND_TRANSFER.getDesc());
            // 学籍资金流转明细
            cn.itcast.nems.order.dto.StudentRecordFundFlowDTO fundFlow = new cn.itcast.nems.order.dto.StudentRecordFundFlowDTO();
            fundFlow.setStudentRecordId(originStudentRecordId);
            fundFlow.setClazzId(clazzId);
            fundFlow.setClazzName(clazzName);
            fundFlow.setReferenceType(ReferenceTypeEnum.FUND_TRANSFER);
            fundFlow.setBizDate(bizDate);
            fundFlow.setReferenceId(id);
            fundFlow.setReferenceLineId(id);
            fundFlow.setPaymentType(FundFlowPaymentTypeEnum.FUND_TRANSFER.name());
            fundFlow.setPaymentNo(id);
            fundFlow.setAmount(amount);
            fundFlow.setCharge(0);
            fundFlow.setPaymentMethodCode("");
            fundFlow.setPaymentMethodName("");
            fundFlow.setPaymentAccountCode(channelCode);
            fundFlow.setPaymentAccountName(channelName);
            fundFlow.setRemark(StringUtils.hasText(remark) ? remark : FundFlowPaymentTypeEnum.FUND_TRANSFER.getDesc());
            fundFlow.setUpdateStudentRecord(Boolean.TRUE);
            flowDTO.setStudentRecordFundFlowDTO(fundFlow);
            orderApi.addPaymentFlow(flowDTO);
        } else {
            StudentRecordPaidDTO studentRecordPaidDTO = new StudentRecordPaidDTO();
            studentRecordPaidDTO.setStudentRecordId(originStudentRecordId);
            studentRecordPaidDTO.setBizDate(bizDate);
            studentRecordPaidDTO.setPaymentType(FundFlowPaymentTypeEnum.FUND_TRANSFER.name());
            studentRecordPaidDTO.setPaymentNo(id);
            studentRecordPaidDTO.setAmount(amount);
            studentRecordPaidDTO.setPaymentMethodCode("");
            studentRecordPaidDTO.setPaymentMethodName("");
            studentRecordPaidDTO.setPaymentAccountCode(channelCode);
            studentRecordPaidDTO.setPaymentAccountName(channelName);
            this.studentRecordPaidApi.studentRecordPaid(studentRecordPaidDTO);
        }
    }

    @Override
    public void approve(String formID, ApprovalFormService.ApproveResult result, String comment, final String form, Integer applyType) {
        ApprovalForm approvalForm = approvalFormService.getByBusinessKey(formID);
        if (approvalForm == null) {
            log.info("【审批完成】未匹配到数据：" + formID);
            return;
        }
//        String campusId = "";
//        String campusName = "";
//        String channelCode = "";
//        String channelName = "";
//        LocalDateTime bizDate = null;
//        if (StringUtils.hasText(form)) {
//            AdditionalFormPaymentchannel additional = JSONArrayToEntityConverter.convert(form, AdditionalFormPaymentchannel.class);
//            cn.hutool.core.lang.Assert.notNull(additional.getBizDate(), () -> new BizException(CustomBizError.message(CustomBizError.PARAM_EMPTY, "付款日期不能为空")));
//            cn.hutool.core.lang.Assert.notNull(additional.getCampusId(), () -> new BizException(CustomBizError.message(CustomBizError.PARAM_EMPTY, "校区不能为空")));
//            cn.hutool.core.lang.Assert.notNull(additional.getChannelCode(), () -> new BizException(CustomBizError.message(CustomBizError.PARAM_EMPTY, "付款渠道不能为空")));
//            campusId = additional.getCampusId();
//            channelCode = additional.getChannelCode();
//            bizDate = additional.getBizDate();
//            if (StringUtils.hasText(campusId)) {
//                // 获取校区名称
//                SchoolDTO schoolDTO = schoolApi.findById(campusId);
//                if (schoolDTO != null) {
//                    campusName = schoolDTO.getName();
//                }
//            }
//
//            if (StringUtils.hasText(channelCode)) {
//                Paymentchannel paymentchannel = paymentchannelService.getById(channelCode);
//                if (paymentchannel != null) {
//                    channelName = paymentchannel.getName();
//                }
//            }
//        }

        String journalId = approvalForm.getJournalId();
        JournalFundTransfer journal = baseMapper.selectById(journalId);
        log.info("【审批完成】查询审批单详情：{}", JSON.toJSONString(approvalForm));
        if (ApprovalFormService.ApproveResult.REJECT == result) {
            // 审批未通过
            lambdaUpdate().eq(JournalFundTransfer::getId, journalId)
                    .set(JournalFundTransfer::getState, JournalStateEnum.REJECTED.name())
//                    .set(StringUtils.hasText(campusId), JournalFundTransfer::getCampusId, campusId)
//                    .set(StringUtils.hasText(campusName), JournalFundTransfer::getCampusName, campusName)
//                    .set(StringUtils.hasText(channelCode), JournalFundTransfer::getChannelCode, channelCode)
//                    .set(StringUtils.hasText(channelName), JournalFundTransfer::getChannelName, channelName)
//                    .set(Objects.nonNull(bizDate), JournalFundTransfer::getBizDate, bizDate)
                    .update();
            studentRecordService.unlock(journal.getOriginStudentRecordId());
        } else {
            JournalStateEnum journalStateEnum = JournalStateEnum.APPROVING;
            //  1：审批（默认））2：驳回到发起人）3：驳回上一级）
            if (applyType != null && applyType == 2) {
                journalStateEnum = JournalStateEnum.DRAFT;
                studentRecordService.unlock(journal.getOriginStudentRecordId());
            } else if (applyType != null && applyType == 3) {
                journalStateEnum = JournalStateEnum.PENDING;
            }
            // 审批通过
            lambdaUpdate().eq(JournalFundTransfer::getId, journalId)
                    .set(JournalFundTransfer::getState, journalStateEnum.name())
//                    .set(StringUtils.hasText(campusId), JournalFundTransfer::getCampusId, campusId)
//                    .set(StringUtils.hasText(campusName), JournalFundTransfer::getCampusName, campusName)
//                    .set(StringUtils.hasText(channelCode), JournalFundTransfer::getChannelCode, channelCode)
//                    .set(StringUtils.hasText(channelName), JournalFundTransfer::getChannelName, channelName)
//                    .set(Objects.nonNull(bizDate), JournalFundTransfer::getBizDate, bizDate)
                    .update();
        }
        approvalFormService.approve(formID, result, comment, form, applyType);
    }

    @Override
    @Transactional
    public void cancel(final String formID) {
        ApprovalForm approvalForm = approvalFormService.getByBusinessKey(formID);
        if (approvalForm == null) {
            log.info("【撤回】未匹配到数据：" + formID);
            return;
        }
        String journalId = approvalForm.getJournalId();
        JournalFundTransfer journal = baseMapper.selectById(journalId);
        cn.hutool.core.lang.Assert.notNull(journal, BizExceptionProducer.produce(NemsErrorBodyEnum.DATA_EXIST, "ID：" + formID));
        // 校验：必须发起人才能撤回
        org.springframework.util.Assert.isTrue(journal.getCreatedBy().equals(AccountHolder.getRequiredAccount()), "必须发起人才能撤回");
        // 撤回-状态改为：草稿
        lambdaUpdate().eq(JournalFundTransfer::getId, journalId).set(JournalFundTransfer::getState, JournalStateEnum.DRAFT.name()).update();
        approvalFormService.cancel(formID);
        // 解锁学籍
        studentRecordService.unlock(journal.getOriginStudentRecordId());

    }

    @Override
    @Transactional
    public void rollbackRequester(String formID) {
        ApprovalForm approvalForm = approvalFormService.getByBusinessKey(formID);
        if (approvalForm == null) {
            log.info("【撤回】未匹配到数据：" + formID);
            return;
        }
        String journalId = approvalForm.getJournalId();
        JournalFundTransfer journal = baseMapper.selectById(journalId);
        cn.hutool.core.lang.Assert.notNull(journal, BizExceptionProducer.produce(NemsErrorBodyEnum.DATA_EXIST, "ID：" + formID));
        if (journal.getState().equals(JournalStateEnum.DRAFT.name())) {
            return;
        }
        // 撤回-状态改为：草稿
        lambdaUpdate().eq(JournalFundTransfer::getId, journalId).set(JournalFundTransfer::getState, JournalStateEnum.DRAFT.name()).update();
//        approvalFormService.cancel(formID);
        // 解锁学籍
        studentRecordService.unlock(journal.getOriginStudentRecordId());
    }

    @Override
    public void remind(String formID, String targetAssignee) {
        String result = approvalFormService.remind(formID, targetAssignee);
        log.info("【调用工作流催办接口】响应正文：" + result);
    }
}
